﻿using Nemerle;
using Nemerle.Collections;
using Nemerle.Text;
using Nemerle.Utility;
using Nemerle2.Compiler;

using System;
using System.Diagnostics;
using System.IO;
using System.Collections.Generic;
using System.Linq;

using TestAssembly;
using NUnit.Framework;

using SCG = System.Collections.Generic;

namespace Test
{
  /// <summary>
  /// Base class for testing MetadataReader
  /// </summary>
  public class AssemblyTests
  {
    private   static _provider : IMetadataProvider;

    protected static Provider : IMetadataProvider { get { _provider; } }

    protected static LoadAssembly(assemblyName : string, assemblyPath : string, provider : IMetadataProvider) : IReferencedAssembly
    {
      Assert.IsTrue(File.Exists(assemblyPath));
      def resultAssembly = provider.LoadAssemblies([assemblyPath]).First();
      Assert.NotNull(resultAssembly);
      Assert.AreEqual(resultAssembly.Name, assemblyName);
      resultAssembly
    }

    protected static GetNemerleAssemblyPath(asmName : string) : string
    {
      def getNemerleInstallDir() : string
      {
        def nemerleEnvVar  = Environment.GetEnvironmentVariable("Nemerle");
        def nemerleInstallDir = nemerleEnvVar ?? Environment.ExpandEnvironmentVariables(@"%ProgramFiles%\Nemerle");
        Assert.NotNull(nemerleInstallDir, "Nemerle 1.0 not installed correctly!");
        nemerleInstallDir
      }

      def installDir      = getNemerleInstallDir();
      def nemerleAsmName  = Path.Combine(installDir, $"$asmName.dll");
      nemerleAsmName
    }

    protected static GetSystemAssemblyPath(asmName : string) : string
    {
#pragma warning disable 618 // Obsolete
      def reflectionAsm   = Reflection.Assembly.LoadWithPartialName(asmName);
#pragma warning restore 618
      def asmPath         = Uri(reflectionAsm.Location).LocalPath;
      asmPath
    }

    private static GetTestAssemblyPath(ty : Type) : string
    {
      Uri(ty.Assembly.Location).LocalPath
    }
    
    //protected static LoadSystemAssemblies(names : Seq[string]) : Seq[IReferencedAssembly]
    //{
    //  names.Map(GetSystemAssemblyPath(_)).Map(LoadAssembly)
    //}
        
    static this()
    {
      _provider = MetadataReader.CCI.CciMetadataProvider();
      
      _ = Threading.ThreadPool.SetMaxThreads(8,8);
    
      AllPaths = [
        AssemblyPath         ,
        MscorlibAssemblyPath ,
        SystemAssemblyPath   ,
        CompilerAssemblyPath ,
        NemerleAssemblyPath  ,
        MacrosAssemblyPath   ,
        CoreAssemblyPath     ,
        DataAssemblyPath     ,
        DrawingAssemblyPath  ,
        WindowsAssemblyPath  ,
        XmlAssemblyPath      ,
        XmlLinqAssemblyPath  ,
      ];
      
      
      def sln = NSolution(_provider);
      AllAssembliesProject = NProject (sln);
      CommonProject = NProject(sln);
      MscoreRefProject = NProject(sln);
      
      def watch = Stopwatch.StartNew();
      _ = AllAssembliesProject.Load([], AllPaths,               []);
      _ = CommonProject.Load       ([], [AssemblyPath, CSharpTestAssemblyPath], []);
      _ = MscoreRefProject.Load    ([], [MscorlibAssemblyPath], []);
            
      Console.WriteLine($"All assemblies load time    = $(watch.Elapsed)");      
    }
    
    protected static AllPaths             : list[string];
    
    internal static CommonProject        : NProject {get; private set; }
    internal static MscoreRefProject     : NProject {get; private set; }
    internal static AllAssembliesProject : NProject {get; private set; }

    public static AssemblyPath           : string = GetTestAssemblyPath(typeof(Program));
    public static CSharpTestAssemblyPath : string = GetTestAssemblyPath(typeof(CSharpTestAssembly.TestEnum));
    public static MscorlibAssemblyPath   : string = GetSystemAssemblyPath ("mscorlib");
    public static SystemAssemblyPath     : string = GetSystemAssemblyPath ("System");
    public static CompilerAssemblyPath   : string = GetNemerleAssemblyPath("Nemerle.Compiler");
    public static NemerleAssemblyPath    : string = GetNemerleAssemblyPath("Nemerle");
    public static MacrosAssemblyPath     : string = GetNemerleAssemblyPath("Nemerle.Macros");
    public static CoreAssemblyPath       : string = GetSystemAssemblyPath("System.Core");
    public static DataAssemblyPath       : string = GetSystemAssemblyPath("System.Data");
    public static DrawingAssemblyPath    : string = GetSystemAssemblyPath("System.Drawing");
    public static WindowsAssemblyPath    : string = GetSystemAssemblyPath("System.Windows.Forms");
    public static XmlAssemblyPath        : string = GetSystemAssemblyPath("System.Xml");
    public static XmlLinqAssemblyPath    : string = GetSystemAssemblyPath("System.Xml.Linq");


   // protected SystemCoreAssembly : IReferencedAssembly { get {GetSystemAssemblyPath("System.Core")} }
  }
}
